<?php

declare(strict_types=1);

namespace App\Admin\Service\Setting;

use DI\DependencyException;
use DI\NotFoundException;
use Newbie\Abstracts\AbstractService;
use Newbie\Generator\ModuleGenerator;
use Newbie\Newbie;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Filesystem\Filesystem;

class ModuleService extends AbstractService {
    /**
     * @var Newbie
     */
    protected Newbie $mine;

    /**
     * @var string
     */
    protected string $prefix = '';

    public function __construct (Newbie $mine) {
        $this->mine = $mine;
    }

    /**
     * 获取表状态分页列表
     * @param array|null $params
     * @param bool $isScope
     * @return array
     */
    public function getPageList (?array $params = [], bool $isScope = true): array {
        return $this->getArrayToPageList($params);
    }

    /**
     * 数组数据搜索器
     */
    protected function handleArraySearch ($collect, array $params) {
        if ($params['name'] ?? false) {
            $collect = $collect->filter(function ($row) use ($params) {
                return \newbie\Helper\Str::contains($row['name'], $params['name']);
            });
        }

        if ($params['label'] ?? false) {
            $collect = $collect->filter(function ($row) use ($params) {
                return \newbie\Helper\Str::contains($row['label'], $params['label']);
            });
        }
        return $collect;
    }

    /**
     * 设置需要分页的数组数据
     * @param array $params
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    protected function getArrayData (array $params = []): array {
        return $this->getModuleCache();
    }

    /**
     * 创建模块
     * @param array $moduleInfo
     * @return bool
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws DependencyException
     * @throws NotFoundException
     */
    public function createModule (array $moduleInfo): bool {
        /** @var ModuleGenerator $moduleGen */
        $moduleGen = container()->make(ModuleGenerator::class);
        $moduleGen->setModuleInfo($moduleInfo)->createModule();
        $this->setModuleCache();
        return true;
    }

    /**
     * 执行模块安装
     * @param string $name
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function installModuleData (string $name): bool {
        try {
            $migrateCommand = ['command' => 'newbie:migrate-run', 'name' => $name];
            $seedCommand    = ['command' => 'newbie:seeder-run', 'name' => $name];
            $application    = container()->get(\Hyperf\Contract\ApplicationInterface::class);
            $application->setAutoExit(false);
            $application->run(new ArrayInput($migrateCommand), new NullOutput());
            $application->run(new ArrayInput($seedCommand), new NullOutput());
            $this->setModuleCache();
            return true;
        } catch (\Throwable $e) {
            return false;
        }
    }

    /**
     * 卸载模块
     * @param string $name
     * @return bool
     * @throws \Throwable
     */
    public function uninstallModule (string $name): bool {
        return true;
    }

    /**
     * 删除模块
     * @param string $name
     * @return bool
     */
    public function deleteModule (string $name): bool {
        $modulePath = BASE_PATH . '/app/' . ucfirst($name);
        return remove_dir($modulePath);
    }

    /**
     * 缓存模块信息
     * @param string|null $moduleName 模块名
     * @param array $data 模块数据
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setModuleCache (?string $moduleName = null, array $data = []): void {
        $key = $this->prefix . 'modules';
        $this->mine->scanModule();
        $modules = $this->mine->getModuleInfo();
        if (!empty($moduleName)) {
            $modules[$moduleName] = $data;
        }
        redis()->set($key, serialize($modules));
    }

    /**
     * 获取模块缓存信息
     * @param string|null $moduleName
     * @return array
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function getModuleCache (?string $moduleName = null): array {
        $key   = $this->prefix . 'modules';
        $redis = redis();
        if ($redis->exists($key)) {
            $data = unserialize($redis->get($key));
            return !empty($moduleName) && isset($data[$moduleName]) ? $data[$moduleName] : $data;
        } else {
            $this->setModuleCache();
            $this->mine->scanModule();
            return $this->mine->getModuleInfo();
        }
    }

    /**
     * 启停用模块
     * @param array $data
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function modifyStatus (array $data): bool {
        $modules = container()->get(Newbie::class)->getModuleInfo();
        if (isset($modules[$data['name']])) {
            $filePath = BASE_PATH . '/app/' . $data['name'] . '/config.json';
            $status   = $data['status'] ? 'true' : 'false';
            $content  = preg_replace(
                '/\"enabled\":\s(true|false),/',
                '"enabled": ' . $status . ',',
                file_get_contents($filePath)
            );
            $result   = (bool)file_put_contents($filePath, $content);
            $this->setModuleCache();
            return $result;
        } else {
            return false;
        }
    }
}